package com.drinkian.authentication.filter;

import com.alibaba.fastjson.JSON;
import com.drinkian.authentication.entity.bo.SecurityUser;
import com.drinkian.entity.RequestResult;
import com.drinkian.utils.JwtUtil;
import com.drinkian.utils.RedisUtil;
import com.drinkian.utils.WebUtil;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 1.1 获得token
        String token = request.getHeader("token");
        // 1.2 不存在token，放行请求，后面还有认证过滤器链，不必担心权限问题
        if (token == null) {
            filterChain.doFilter(request, response);
            return;
        }

        // 2.1 解析token获得user_id
        Integer userId = null;
        try {
            userId = jwtUtil.parseToken(token);
        } catch (MalformedJwtException e) {
            RequestResult requestResult = new RequestResult(HttpStatus.UNAUTHORIZED.value(), "身份令牌被篡改，请重新登录");
            WebUtil.send(response, JSON.toJSONString(requestResult));
            return;
        } catch (SignatureException e) {
            RequestResult requestResult = new RequestResult(HttpStatus.UNAUTHORIZED.value(), "身份令牌被篡改，请重新登录");
            WebUtil.send(response, JSON.toJSONString(requestResult));
            return;
        } catch (ExpiredJwtException e) {
            RequestResult requestResult = new RequestResult(HttpStatus.UNAUTHORIZED.value(), "身份过期，请重新登录");
            WebUtil.send(response, JSON.toJSONString(requestResult));
            return;
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        // 3.1 从redis中取得用户信息
        SecurityUser securityUser = redisUtil.get("user_id_" + userId, SecurityUser.class);
        if (Objects.isNull(securityUser)) {
            throw new RuntimeException("用户未登录");
        }

        // 4.1 存入SecurityContextHolder
        //      ps：这里一定要使用三个参数的构造函数，因为这里面会设值认证标志位为true
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

        // 5.1 放行请求
        filterChain.doFilter(request, response);
    }
}
